/*
 * Copyright (c) 2025 Industrial Software Feature Database
 */
package com.comac.ins.bomt.service.impl;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.comac.ins.bomt.domain.*;
import com.comac.ins.bomt.domain.vo.*;
import com.comac.ins.bomt.service.*;
import com.comac.ins.common.biz.domain.vo.BizEventInfoVo;
import com.comac.ins.common.biz.event.BizEventService;
import com.comac.ins.common.core.domain.model.LoginUser;
import com.comac.ins.common.biz.exception.BizException;
import com.comac.ins.common.biz.utils.BizAssertUtil;
import com.comac.ins.common.core.utils.MapstructUtils;
import com.comac.ins.common.excel.utils.ExcelUtil;
import com.comac.ins.common.json.utils.JsonUtils;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.text.MessageFormat;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * Bom导出服务
 *
 * @author zhanghongyi
 * @date 2024/8/23
 * @description BomExportServiceImpl
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class BomExportServiceV2Impl implements BomExportServiceV2 {

    private final BizFileService bizFileService;

    private final BomQueryServiceV2 bomQueryServiceV2;

    private final BomGenerateServiceV2 bomGenerateServiceV2;
    private final SectionService sectionService;

    public void exportStandardBom(LoginUser loginUser, Long standardBomId,HttpServletResponse response) {
        StandardBomV2Info standardBomInfo = bomQueryServiceV2.queryStandardBomInfoById(loginUser, standardBomId);
        BizAssertUtil.notNull(standardBomInfo, "standardBomInfo not found");
        Map<String, String> reverseGroupConfig = sectionService.getReverseSectionGroupConfig(standardBomInfo.getAircraftModel(), standardBomInfo.getTrack());
        BizAssertUtil.isTrue(reverseGroupConfig.containsKey(standardBomInfo.getSection()), MessageFormat.format("未找到机型:{0},批次号:{1},部段:{2}对应的编码,请前往构型定义添加",standardBomInfo.getAircraftModel(),standardBomInfo.getTrack(),standardBomInfo.getSection()));
        String groupType = reverseGroupConfig.get(standardBomInfo.getSection());
        List<DetailStandardV2Bom> standardDetails = bomQueryServiceV2.queryStandardBomDetailByInfoId(loginUser, standardBomInfo.getAircraftModel(),standardBomInfo.getId());
        List<DetailStandardV2BomVo> standardDetailVos = MapstructUtils.convert(standardDetails, DetailStandardV2BomVo.class);
        //导出文件
        String exportFileName = StringUtils.join(Arrays.asList(groupType, "标准装机清单"), "_");
        try {
            File tmpExportFile = File.createTempFile(exportFileName, ".xlsx");
            try (FileOutputStream os = new FileOutputStream(tmpExportFile)) {
                ExcelUtil.exportExcel(standardDetailVos, groupType, DetailStandardV2BomVo.class, os);
            }
            writeResponse(loginUser, List.of(tmpExportFile),List.of(exportFileName+".xlsx"), response);
            tmpExportFile.delete();
        } catch (Exception e) {
            log.error(MessageFormat.format("export {0} error", exportFileName), e);
            throw new BizException(MessageFormat.format("export {0} error:{1}", exportFileName, e.getMessage()));
        }
    }

    public void exportStrengthBom(LoginUser loginUser, Long strengthBomId,HttpServletResponse response) {
        StrengthBomV2Info strengthBomInfo = bomQueryServiceV2.queryStrengthBomInfoById(loginUser, strengthBomId);
        BizAssertUtil.notNull(strengthBomInfo, "strengthBomInfo not found");

        List<DetailStrengthV2Bom> strengthDetails = bomQueryServiceV2.queryStrengthDetail(loginUser,strengthBomInfo.getAircraftModel(),strengthBomInfo.getTrack(),strengthBomInfo.getGroupType());
        List<DetailStrengthV2BomVo> strengthDetailVos = MapstructUtils.convert(strengthDetails, DetailStrengthV2BomVo.class);
        //导出并上传文件
        String exportFileName = StringUtils.join(Arrays.asList(strengthBomInfo.getGroupType(), "强度数模清单"), "_");
        try {
            File tmpExportFile = File.createTempFile(exportFileName, ".xlsx");
            try (FileOutputStream os = new FileOutputStream(tmpExportFile)) {
                DetailStrengthV2BomVo.exportStrengthBom(os, strengthBomInfo.getGroupType(), strengthDetailVos);
            }
            writeResponse(loginUser, List.of(tmpExportFile),List.of(exportFileName+".xlsx"), response);
        } catch (Exception e) {
            log.error(MessageFormat.format("export {0} error", exportFileName), e);
            throw new BizException(MessageFormat.format("export {0} error:{1}", exportFileName, e.getMessage()));
        }
    }

    public void exportStrengthCompare(LoginUser loginUser, String leftAircraftModel,String leftTrack,String leftGroupType,String rightAircraftModel,String rightTrack,String rightGroupType,HttpServletResponse response){
        Long eventInfoId = bomGenerateServiceV2.beginCompareStrength(loginUser, leftAircraftModel, leftTrack, leftGroupType, rightAircraftModel, rightTrack, rightGroupType, false);
        BizEventInfoVo eventInfo = BizEventService.queryEventInfoById(eventInfoId);
        BizAssertUtil.notNull(eventInfo,"eventInfo not found");
        BizAssertUtil.notBlank(eventInfo.getReturnResult(),"eventInfo.return result is null");
        StrengthBomChangeV2InfoVo compareResult = JsonUtils.parseObject(eventInfo.getReturnResult(), StrengthBomChangeV2InfoVo.class);
        BizAssertUtil.notNull(compareResult,"parsed compareResult is null");
        //导出文件
        String exportFileName = StringUtils.join(Arrays.asList(leftGroupType,leftTrack,rightTrack, "强度清单对比结果"), "_");
        try {
            File tmpExportFile = File.createTempFile(exportFileName, ".xlsx");
            try (FileOutputStream os = new FileOutputStream(tmpExportFile);ExcelWriter excelWriter = EasyExcel.write(os).build();) {
                WriteSheet writeSheet = EasyExcel.writerSheet(0,"需更新").head(DetailStrengthV2BomChangeVo.class).build();
                excelWriter.write(compareResult.getDiff(),writeSheet);
                writeSheet = EasyExcel.writerSheet(1,"可复用").head(DetailStrengthV2BomChangeVo.class).build();
                excelWriter.write(compareResult.getSame(),writeSheet);
                excelWriter.finish();
            }
            writeResponse(loginUser, List.of(tmpExportFile),List.of(exportFileName+".xlsx"), response);
            tmpExportFile.delete();
        } catch (Exception e) {
            log.error(MessageFormat.format("export {0} error", exportFileName), e);
            throw new BizException(MessageFormat.format("export {0} error:{1}", exportFileName, e.getMessage()));
        }
    }


    public void writeResponse(LoginUser loginUser,List<File> fileList,List<String> fileNames,HttpServletResponse response) {
        BizAssertUtil.notEmpty(fileList, "fileList is empty");
        try {
            //写入下载
            try {
                File[] files = fileList.toArray(new File[0]);
                response.setContentType("application/octet-stream");
                if (files.length > 1) {
                    response.setHeader("Content-Disposition", "attachment; filename=\"download.zip\"");
                    try (OutputStream zipOs = response.getOutputStream()) {
                        writeToZip(zipOs, files, fileNames.toArray(new String[0]));
                    }
                } else {
                    response.setHeader("Content-Disposition", MessageFormat.format("attachment; filename=\"{0}\"", URLEncoder.encode(fileNames.get(0), StandardCharsets.UTF_8)));
                    try (OutputStream os = response.getOutputStream()) {
                        os.write(Files.readAllBytes(files[0].toPath()));
                    }
                }
            } catch (IOException e) {
                throw new BizException("write to zip fail", e);
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new BizException("write fail", e);
        }
    }
    private void writeToZip(OutputStream outputZip, File[] files, String[] fileNames) {
        try (ZipOutputStream zip = new ZipOutputStream(outputZip)) {
            for (int i = 0; i < files.length; i++) {
                zip.putNextEntry(new ZipEntry(fileNames == null ? files[i].getName() : fileNames[i]));
                zip.write(Files.readAllBytes(files[i].toPath()));
                zip.closeEntry();
            }
        } catch (IOException e) {
            throw new BizException("export to zip fail", e);
        }
    }
}
